#!/usr/bin/python
# -*- coding: utf-8 -*-

from constante import *
import random

def getOpcodeSignature():
	""" opcode : (Mask, Signature, Function)"""
	opcode = 		((0x0000, 0x0FFF, i0x0FFF),
					(0xFFFF, 0x00E0, i0x00E0),
					(0xFFFF, 0x00EE, i0x00EE),
					(0xF000, 0x1000, i0x1000),
					(0xF000, 0x2000, i0x2000),
					(0xF000, 0x3000, i0x3000),
					(0xF000, 0x4000, i0x4000),
					(0xF00F, 0x5000, i0x5000),
					(0xF000, 0x6000, i0x6000),
					(0xF000, 0x7000, i0x7000),
					(0xF00F, 0x8000, i0x8000),
					(0xF00F, 0x8001, i0x8001),
					(0xF00F, 0x8002, i0x8002),
					(0xF00F, 0x8003, i0x8003),
					(0xF00F, 0x8004, i0x8004),
					(0xF00F, 0x8005, i0x8005),
					(0xF00F, 0x8006, i0x8006),
					(0xF00F, 0x8007, i0x8007),
					(0xF00F, 0x800E, i0x800E),
					(0xF00F, 0x9000, i0x9000),
					(0xF000, 0xA000, i0xA000),
					(0xF000, 0xB000, i0xB000),
					(0xF000, 0xC000, i0xC000),
					(0xF000, 0xD000, i0xD000),
					(0xF0FF, 0xE09E, i0xE09E),
					(0xF0FF, 0xE0A1, i0xE0A1),
					(0xF0FF, 0xF007, i0xF007),
					(0xF0FF, 0xF00A, i0xF00A),
					(0xF0FF, 0xF015, i0xF015),
					(0xF0FF, 0xF018, i0xF018),
					(0xF0FF, 0xF029, i0xF029),
					(0xF0FF, 0xF01E, i0xF01E),
					(0xF0FF, 0xF033, i0xF033),
					(0xF0FF, 0xF055, i0xF055),
					(0xF0FF, 0xF065, i0xF065))
	return opcode


def i0x0FFF(self, b1, b2, b3):
	""" 0NNN : 	Calls RCA 1802 program at address NNN
	WARNING: Not implemented"""
	pass
	
def i0x00E0(self, b1, b2, b3):
	""" 00E0 : Clears the screen"""
	for x in xrange(SCR_WIDTH):
		for y in xrange(SCR_HEIGHT):
			self.bg[x,y] = BLACK

def i0x00EE(self, b1, b2, b3):
	""" 00EE : Returns from a subroutine"""
	if self.pointStack > 0:
		self.pointStack -= 1
		self.pointRam = self.stack[self.pointStack]


def i0x1000(self, b1, b2, b3):
	""" 1NNN : Jumps to address NNN"""
	self.pointRam = (b3<<8) + (b2<<4) + b1
	self.pointRam -= 2

def i0x2000(self, b1, b2, b3):
	""" 2NNN : Calls subroutine at NNN"""
	self.stack[self.pointStack] = self.pointRam
	if self.pointStack < 0xF:
		self.pointStack += 1
	self.pointRam = (b3<<8) + (b2<<4) + b1
	self.pointRam -= 2

def i0x3000(self, b1, b2, b3):
	""" 3XNN : Skips the next instruction if VX equals NN"""
	if self.register[b3] == (b2<<4) + b1:
		self.pointRam += 2

def i0x4000(self, b1, b2, b3):
	""" 4XNN : Skips the next instruction if VX doesn't equal NN"""
	if self.register[b3] != (b2<<4) + b1:
		self.pointRam += 2

def i0x5000(self, b1, b2, b3):
	""" 5XY0 : Skips the next instruction if VX equals VY."""
	if self.register[b3] == self.register[b2]:
		self.pointRam += 2

def i0x6000(self, b1, b2, b3):
	""" 6XNN : Sets VX to NN"""
	self.register[b3] = (b2<<4) + b1

def i0x7000(self, b1, b2, b3):
	""" 7XNN : Adds NN to VX"""
	self.register[b3] += (b2<<4) + b1

def i0x8000(self, b1, b2, b3):
	""" 8XY0 : Sets VX to the value of VY"""
	self.register[b3] = self.register[b2]

def i0x8001(self, b1, b2, b3):
	""" 8XY1 : Sets VX to VX or VY"""
	self.register[b3] = self.register[b3] | self.register[b2]

def i0x8002(self, b1, b2, b3):
	""" 8XY2 : Sets VX to VX and VY"""
	self.register[b3] = self.register[b3] & self.register[b2]

def i0x8003(self, b1, b2, b3):
	""" 8XY3 : Sets VX to VX xor VY"""
	self.register[b3] = self.register[b3] ^ self.register[b2]

def i0x8004(self, b1, b2, b3):
	""" 8XY4 : Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't"""
	if (self.register[b3] + self.register[b2]) > 0xFF:
		self.register[0xF] = 1
	else:
		self.register[0xF] = 0
	self.register[b3] += self.register[b2]

def i0x8005(self, b1, b2, b3):
	""" 8XY5 : VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't."""
	if self.register[b3] < self.register[b2]:
		self.register[0xF] = 0
	else:
		self.register[0xF] = 1
	self.register[b3] -= self.register[b2]

def i0x8006(self, b1, b2, b3):
	""" 8XY6 : Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift"""
	self.register[0xF] = self.register[b3] & 0x1
	self.register[b3] = self.register[b3] >> 1

def i0x8007(self, b1, b2, b3):
	""" 8XY7 : Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't"""
	if self.register[b2] < self.register[b3]:
		self.register[0xF] = 0
	else:
		self.register[0xF] = 1
	self.register[b3] = self.register[b2] - self.register[b3]

def i0x800E(self, b1, b2, b3):
	""" 8XYE : Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift"""
	self.register[0xF] = self.register[b3] >> 0x7
	self.register[b3] = self.register[b3] << 1

def i0x9000(self, b1, b2, b3):
	""" 9XY0 : Skips the next instruction if VX doesn't equal VY"""
	if self.register[b3] != self.register[b2]:
		self.pointRam += 2

def i0xA000(self, b1, b2, b3):
	""" ANNN : Sets I to the address NNN."""
	self.pointReg = (b3 << 8) + (b2 << 4) + b1

def i0xB000(self, b1, b2, b3):
	""" BNNN : Jumps to the address NNN plus V0"""
	self.pointRam = (b3 << 8) + (b2 << 4) + b1 + self.register[0]
	self.pointRam -= 2

def i0xC000(self, b1, b2, b3):
	""" CXNN : Sets VX to a random number and NN"""
	self.register[b3] = random.randint(0, (b2<<4)+b1+1)

def i0xD000(self, b1, b2, b3):
	""" DXYN : Draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and a height of N pixels.
	Each row of 8 pixels is read as bit-coded (with the most significant bit of each byte displayed on the left)
	starting from memory location I; I value doesn't change after the execution of this instruction.
	As described above, VF is set to 1 if any screen pixels are flipped from set to unset when the sprite is drawn,
	and to 0 if that doesn't happen."""
	self.register[0xF] = 0
	for k in xrange(b1):
		codage = self.br[self.pointReg+k]
		y = (self.register[b2] + k) % SCR_HEIGHT
		for j in xrange(8):
			x = (self.register[b3] + j) % SCR_WIDTH
			if (codage & (0x1<<(7-j))) != 0:
				if self.bg[x,y] == WHITE:
					self.bg[x,y] = BLACK
					self.register[0xF] = 1
				else:
					self.bg[x,y] = WHITE

def i0xE09E(self, b1, b2, b3):
	""" EX9E : Skips the next instruction if the key stored in VX is pressed"""
	if self.bus_input[b3]:
		self.pointRam += 2

def i0xE0A1(self, b1, b2, b3):
	""" EXA1 : Skips the next instruction if the key stored in VX isn't pressed"""
	if not self.bus_input[b3]:
		self.pointRam += 2

def i0xF007(self, b1, b2, b3):
	""" FX07 : Sets VX to the value of the delay timer."""
	self.register[b3] = self.clockCPU

def i0xF00A(self, b1, b2, b3):
	""" FX0A : A key press is awaited, and then stored in VX"""
	pass

def i0xF015(self, b1, b2, b3):
	""" FX15 : 	Sets the delay timer to VX"""
	self.clockCPU = self.register[b3]

def i0xF018(self, b1, b2, b3):
	""" """
	pass

def i0xF01E(self, b1, b2, b3):
	""" FX1E : Adds VX to I.
	VF is set to 1 when range overflow (I+VX>0xFFF),
	and 0 when there isn't."""
	if (self.pointReg + self.register[b3]) > 0xFFF:
		self.register[0xF] = 1
	else:
		self.register[0xF] = 0
	self.pointReg += self.register[b3]

def i0xF029(self, b1, b2, b3):
	""" FX29 : Sets I to the location of the sprite for the character in VX. 
	Characters 0-F (in hexadecimal) are represented by a 4x5 font"""
	self.pointReg = 5*self.register[b3]

def i0xF033(self, b1, b2, b3):
	""" FX33 : Stores the Binary-coded decimal representation of VX, 
	with the most significant of three digits at the address in I, 
	the middle digit at I plus 1, and the least significant digit 
	at I plus 2."""
	self.br[self.pointReg] = (self.register[b3] - self.register[b3] % 100) / 100
	self.br[self.pointReg+1] = ((self.register[b3] - self.register[b3] % 10) / 10) %10
	self.br[self.pointReg+2] = self.register[b3] - self.br[self.pointReg] * 100 - self.br[self.pointReg + 1] * 10

def i0xF055(self, b1, b2, b3):
	""" FX55 : Stores V0 to VX in memory starting at address I"""
	for i in xrange(b3+1):
		self.br[self.pointReg + i] = self.register[i]

def i0xF065(self, b1, b2, b3):
	""" FX65 : Fills V0 to VX with values from memory starting at address I"""
	for i in xrange(b3+1):
		self.register[i] = self.br[self.pointReg + i]
